home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
xbomb-2.0
/
xbomb-2
/
xbomb
/
xbomb.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-16
|
9KB
|
442 lines
/***************************************
$Header: /home/amb/xbomb/RCS/xbomb.c 1.9 1995/11/16 20:16:39 amb Exp $
XBomb - 'Minesweeper' game - Version 2
Main function of program - excludes all window interface parts.
Written by Andrew M. Bishop
This file Copyright 1994 1995 Andrew M. Bishop
It may be distributed under the GNU Public License, version 2, or
any higher version. See section COPYING of the GNU Public license
for conditions under which this file may be redistributed.
***************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "xbomb.h"
#if defined(__sun__) && !defined(__svr4__)
int printf(const char*, ... );
int tolower (int c);
time_t time(time_t *t);
int rand(void);
#endif
static int count_adjacent(int x,int y,int flag);
int grid_width,grid_height,grid_bombs,grid_level,grid_type;
char levels[NLEVELS][LEVELSLEN]=LEVELS;
char types [NTYPES] [TYPESLEN] =TYPES;
int widths [NLEVELS]=WIDTHS;
int heights[NLEVELS]=HEIGHTS;
int nbombs [NLEVELS]=NBOMBS;
static int status=GAME_WAIT;
static unsigned char state[MAX_SIZE][MAX_SIZE];
static int n_unseen,n_think,ticks;
/*++++++++++++++++++++++++++++++++++++++
The main program.
int argc The command line parameters.
char** argv The command line parameters.
++++++++++++++++++++++++++++++++++++++*/
void main(int argc,char** argv)
{
int level=0,type=GAME_SQUARE; /* Default values. */
int xstatus=0;
long t;
printf("\n XBomb Version 2\n --------------- (c) AMB Software 1995\n\n");
if(argc>1)
{
int i,j;
for(j=0;j<NLEVELS;j++)
{
char levstr[3];
sprintf(levstr,"-%1d",j+1);
for(i=1;i<argc;i++)
if(!strcmp(levstr,argv[i]))
level=j;
}
for(j=0;j<NTYPES;j++)
{
char typstr[TYPESLEN+1];
sprintf(typstr,"-%s",types[j]);
for(i=1;i<strlen(typstr);i++)
typstr[i]=tolower(typstr[i]);
for(i=1;i<argc;i++)
if(!strncmp(typstr,argv[i],strlen(argv[i])))
type=GAME_TYPE+j;
}
for(i=1;i<argc;i++)
if(strlen(argv[i])>2 && !strncmp("-hiscore",argv[i],strlen(argv[i])))
{
grid_type=type;
PrintHighScores(-1);
exit(0);
}
}
t=time(&t);
srand((unsigned int)t);
InitialiseX(&argc,argv);
StartGame(level,type);
for(;;)
{
xstatus=ProcessXEvents();
if(xstatus==GAME_QUIT)
break;
else
if(xstatus==GAME_START)
{
if(status==GAME_CONTINUES)
StopGame();
StartGame(level,type);
}
else
if(xstatus>=GAME_LEVEL && xstatus<(GAME_LEVEL+NLEVELS))
level=xstatus-GAME_LEVEL;
else
if(xstatus>=GAME_TYPE && xstatus<(GAME_TYPE+NTYPES))
type=xstatus;
switch(status)
{
case GAME_WON:
StopGame();
printf("WON! on %s level of %s\n",levels[grid_level],types[grid_type-GAME_TYPE]);
AddHighScore(grid_level,ticks);
break;
case GAME_LOST:
StopGame();
printf("LOST! on %s level of %s\n",levels[grid_level],types[grid_type-GAME_TYPE]);
break;
default:;
}
}
FinishUpX();
}
/*++++++++++++++++++++++++++++++++++++++
Start a new game.
int level The level of the game to play.
int type The type of game to play.
++++++++++++++++++++++++++++++++++++++*/
void StartGame(int level,int type)
{
int x,y;
grid_type=type;
grid_level=level;
grid_width=widths[level];
grid_height=heights[level];
grid_bombs=nbombs[level];
n_unseen=grid_width*grid_height;
n_think=0;
status=GAME_READY;
for(x=0;x<grid_width;x++)
for(y=0;y<grid_height;y++)
state[x][y]=UNSEEN;
ScaleWindow();
DrawGrid();
StartClock(0);
SetUXB(grid_bombs);
}
/*++++++++++++++++++++++++++++++++++++++
Hides the bombs in the grid.
int xs The location that has no neighbouring bombs.
int ys The location that has no neighbouring bombs.
++++++++++++++++++++++++++++++++++++++*/
void HideBombs(int xs,int ys)
{
int i,x,y;
state[xs][ys]+=CORRECT;
for(i=0;i<grid_bombs;i++)
{
do{
x=(rand()>>8)%grid_width;
y=(rand()>>8)%grid_height;
}
while(state[x][y]!=UNSEEN || count_adjacent(x,y,CORRECT));
state[x][y]+=ACTUAL_BOMB;
}
state[xs][ys]-=CORRECT;
for(x=0;x<grid_width;x++)
for(y=0;y<grid_height;y++)
if(!(state[x][y]&ACTUAL_BOMB))
state[x][y]+=count_adjacent(x,y,ACTUAL_BOMB);
StartClock(1);
}
/*++++++++++++++++++++++++++++++++++++++
Stop the game.
++++++++++++++++++++++++++++++++++++++*/
void StopGame(void)
{
status=GAME_WAIT;
ticks=StopClock();
}
/*++++++++++++++++++++++++++++++++++++++
Draws the grid at the start of the game or for expose events.
++++++++++++++++++++++++++++++++++++++*/
void DrawGrid(void)
{
int x,y;
for(x=0;x<grid_width;x++)
for(y=0;y<grid_height;y++)
DrawSquare(x,y,state[x][y]);
}
/*++++++++++++++++++++++++++++++++++++++
The function that is called when a single square is selected.
int x The location of the square.
int y The location of the square.
++++++++++++++++++++++++++++++++++++++*/
void SelectSquare(int x,int y)
{
if(!(state[x][y]&UNSEEN) || state[x][y]&THINK_BOMB || status==GAME_WAIT)
return;
if(status==GAME_READY)
{
HideBombs(x,y);
status=GAME_CONTINUES;
}
RemoveEmpties(x,y);
if(state[x][y]&ACTUAL_BOMB)
{
int x,y;
for(x=0;x<grid_width;x++)
for(y=0;y<grid_width;y++)
if(state[x][y]&UNSEEN)
{
state[x][y]&=~UNSEEN;
if(state[x][y]&THINK_BOMB && state[x][y]&ACTUAL_BOMB)
state[x][y]|=CORRECT;
}
else
state[x][y]|=CORRECT;
status=GAME_LOST;
DrawGrid();
}
else
{
DrawSquare(x,y,state[x][y]);
if(n_think==n_unseen)
status=GAME_WON;
}
}
/*++++++++++++++++++++++++++++++++++++++
Select all of the squares adjacent
int x The location of the square.
int y The location of the square.
++++++++++++++++++++++++++++++++++++++*/
void SelectAdjacent(int x,int y)
{
int dx,dy,n,dd=(grid_type==GAME_TRIANGLE?2:1);
if(state[x][y]&UNSEEN || status==GAME_WAIT)
return;
n=count_adjacent(x,y,THINK_BOMB);
if(state[x][y]!=n)
return;
for(dx=-dd;dx<=dd;dx++)
{
if((x+dx)<0 || (x+dx)>=grid_width)
continue;
for(dy=-1;dy<=1;dy++)
{
if((y+dy)<0 || (y+dy)>=grid_height)
continue;
if(dx==0 && dy==0)
continue;
if(grid_type==GAME_HEXAGON && dy!=0 && dx==(1-2*(y%2)))
continue;
if(grid_type==GAME_TRIANGLE && dy==(2*((x+y)%2)-1) && (dx==-2 || dx==2))
continue;
if(!(state[x+dx][y+dy]&THINK_BOMB))
SelectSquare(x+dx,y+dy);
}
}
}
/*++++++++++++++++++++++++++++++++++++++
Marks as a bomb the square.
int x The location of the square.
int y The location of the square.
++++++++++++++++++++++++++++++++++++++*/
void MarkBomb(int x,int y)
{
if(!(state[x][y]&UNSEEN) || status==GAME_WAIT)
return;
if(n_think==grid_bombs && !(state[x][y]&THINK_BOMB))
return;
state[x][y]^=THINK_BOMB;
if(state[x][y]&THINK_BOMB)
n_think++;
else
n_think--;
SetUXB(grid_bombs-n_think);
DrawSquare(x,y,state[x][y]);
if(n_think==n_unseen)
status=GAME_WON;
}
/*++++++++++++++++++++++++++++++++++++++
Removes the empty squares around here
int x Start from this position.
int y Start from this position.
++++++++++++++++++++++++++++++++++++++*/
void RemoveEmpties(int x, int y)
{
int dx,dy,dd=(grid_type==GAME_TRIANGLE?2:1);
if(!(state[x][y]&UNSEEN) || state[x][y]&THINK_BOMB)
return;
state[x][y]&=~UNSEEN;
n_unseen--;
DrawSquare(x,y,state[x][y]);
if(state[x][y]!=EMPTY)
return;
for(dx=-dd;dx<=dd;dx++)
{
if((x+dx)<0 || (x+dx)>=grid_width)
continue;
for(dy=-1;dy<=1;dy++)
{
if((y+dy)<0 || (y+dy)>=grid_height)
continue;
if(dx==0 && dy==0)
continue;
if(grid_type==GAME_HEXAGON && dy!=0 && dx==(1-2*(y%2)))
continue;
if(grid_type==GAME_TRIANGLE && dy==(2*((x+y)%2)-1) && (dx==-2 || dx==2))
continue;
RemoveEmpties(x+dx,y+dy);
}
}
}
/*++++++++++++++++++++++++++++++++++++++
Count the number of adjacent squares that are bombs.
int count_adjacent Returns the number of adjacent bombs.
int x The position to start from.
int y The position to start from.
int flag The type of bomb to look for.
++++++++++++++++++++++++++++++++++++++*/
static int count_adjacent(int x,int y,int flag)
{
int n=0,dx,dy,dd=(grid_type==GAME_TRIANGLE?2:1);
for(dx=-dd;dx<=dd;dx++)
{
if((x+dx)<0 || (x+dx)>=grid_width)
continue;
for(dy=-1;dy<=1;dy++)
{
if((y+dy)<0 || (y+dy)>=grid_height)
continue;
if(grid_type==GAME_HEXAGON && dy!=0 && dx==(1-2*(y%2)))
continue;
if(grid_type==GAME_TRIANGLE && dy==(2*((x+y)%2)-1) && (dx==-2 || dx==2))
continue;
if(state[x+dx][y+dy]&flag)
n++;
}
}
return(n);
}